﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;

namespace eProject.Model
{
    /// <summary>
    /// This class represents task data
    /// </summary>
    public class Task:INotifyPropertyChanged
    {

        #region Properties
        private string _name;
        public string Name
        {
            get{ return _name;}
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value", "Name cannot be null");
                }
                _name = value;
                InvokeTaskChanged(this);
                InvokePropertyChanged(new PropertyChangedEventArgs("Name"));
            }
        }

        private string _description;
        public string Description
        {
            get { return _description; }
            set
            {                
                _description = value ?? "";
                InvokeTaskChanged(this);
                InvokePropertyChanged(new PropertyChangedEventArgs("Description"));
            }            
        }

        private long _duration;//TODO think about this property
        public long Duration
        {
            get { return _duration; }
            set
            {
                if (value <= 0)
                {
                    throw new ArgumentException("Duration must be greater than zero");
                }
                _duration = value;
                InvokeTaskChanged(this);
                InvokePropertyChanged(new PropertyChangedEventArgs("Duration"));
            }
        }
       // private long Id{ get{ return Id;}}

        public double ManHours { get; private set; }

        public IEnumerable<Activity> Activities { get { return Activity.GetActivities(this); } }

        #endregion

        #region Constructor
        public Task(string name, string description, long duration)
        {
            if (name == null)
            {
                throw new ArgumentNullException("name");
            }
            if (description == null)
            {
                throw new ArgumentNullException("description");
            }
            if (name == "")
            {
                throw new ArgumentException("The name must not be empty");
            }

            if (duration < 0)
            {
                throw new ArgumentException("The duration must be greater than zero");
            }
           
            Name = name;
            Description = description;
            Duration = duration;
        }
        #endregion

        #region Public Methods
        public Activity CreateActivity(Employee employee, Period period, int priority)
        {
            var act = Activity.CreateActivity(this, employee, period, priority);
            act.ManHoursChanged += OnManHoursChanged;
            RecalculateManHours();
            InvokePropertyChanged(new PropertyChangedEventArgs("Activities"));
            return act;
        }

        public void DeleteActivity(Activity activity)
        {
            if (activity == null)
            {
                throw new ArgumentNullException("activity");
            }
            if (activity.Task != this)
            {
                throw new ArgumentException("Task doesn't contain this activity");//TODO message
            }
            activity.ManHoursChanged -= OnManHoursChanged;
            Activity.DeleteActivity(activity);            
            RecalculateManHours();
            InvokePropertyChanged(new PropertyChangedEventArgs("Activities"));
        }

        #endregion

        #region Private Methods
        private void OnManHoursChanged(Activity activity)
        {
            RecalculateManHours();
        }

        private void RecalculateManHours()
        {
            var acts = Activity.GetActivities(this);

            double sum = 0;
            foreach (var act in acts)
            {
                sum += act.ManHours;
            }
            if (ManHours != sum)
            {
                InvokeTaskChanged(this);
                InvokePropertyChanged(new PropertyChangedEventArgs("ManHours"));
            }
            ManHours = sum;
        }

        #endregion

        #region Events

        public delegate void TaskChangedEventHandler(Task task);

        public event TaskChangedEventHandler TaskChanged;

        private void InvokeTaskChanged(Task task)
        {
            var changed = TaskChanged;
            if (changed != null) changed(task);
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void InvokePropertyChanged(PropertyChangedEventArgs e)
        {
            var changed = PropertyChanged;
            if (changed != null) changed(this, e);
        }

        #endregion
        
    }
}
